package com.pubinfo.passbook.data.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pubinfo.passbook.common.entity.*;
import com.pubinfo.passbook.common.mapper.TFileInfoMapper;
import com.pubinfo.passbook.common.model.dto.file.ArtificialFileParam;
import com.pubinfo.passbook.common.model.dto.file.ArtificialParam;
import com.pubinfo.passbook.common.model.dto.file.FileListParam;
import com.pubinfo.passbook.common.model.dto.open.WiteoffAttchment;
import com.pubinfo.passbook.data.service.FtpService;
import com.pubinfo.passbook.data.service.TFileInfoService;
import lombok.SneakyThrows;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@Service
public class TFileInfoServiceImpl extends ServiceImpl<TFileInfoMapper, TFileInfo> implements TFileInfoService {
  
  @Value("${file.uploadFolder}")
  private String filePath;
  
  @Autowired
  FtpService ftpService;
  
  @Override
  public TFileEnclosureFtp saveFile(TFileInfo tFileInfo) {
    if (save(tFileInfo)) {
      try {
        return ftpService.uploadEnclosureFile(tFileInfo.getId());
      } catch (IOException e) {
        log.error("文件上传失败");
      }
    }
    return null;
  }
  
  @Override
  public TFileEnclosureFtp saveTFileEnclosure(MultipartFile file) throws IOException {
    TFileInfo tFileInfo = createTFileInfoByMultipartFile(file, filePath, file.getOriginalFilename());
    tFileInfo.setType(3);
    if (save(tFileInfo)) {
      upload(file, tFileInfo.getPath());
      try {
        return ftpService.uploadEnclosureFile(tFileInfo.getId());
      } catch (IOException e) {
        log.error("文件上传失败");
      }
    }
    return null;
  }
  
  @Override
  public Boolean saveArtificialFile(ArtificialFileParam artificialFileParam) throws IOException {
    List<TFileInfo> tFileInfoList = new ArrayList<>();
    for (MultipartFile file : artificialFileParam.getInvoiceFile()) {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(file, filePath, file.getOriginalFilename());
      tFileInfo.setType(artificialFileParam.getType());
      tFileInfo.setArtificialId(artificialFileParam.getArtificialId());
      tFileInfoList.add(tFileInfo);
    }
    if (!CollectionUtils.isEmpty(tFileInfoList) && saveBatch(tFileInfoList)) {
      uploadList(artificialFileParam.getInvoiceFile(), tFileInfoList);
      return uploadListFtp(tFileInfoList);
    }
    return false;
  }
  
  @Override
  public IPage<TFileInfo> selectFileInfoByFileListParam(FileListParam fileListParam) {
    IPage<TFileInfo> iPage = page(fileListParam.getPage());
    return this.baseMapper.selectFileInfoByFileListParam(iPage, fileListParam);
  }
  
  @Override
  public List<TFileInfo> selectByArtificialId(String artificialId) {
    return baseMapper.selectByArtificialId(artificialId);
  }
  
  @Override
  public Boolean uploadArtificial(ArtificialParam artificialParam, String artificialId, String path) throws IOException {
    List<TFileInfo> invoiceFileList = new ArrayList<>();
    List<TFileInfo> passbookFileList = new ArrayList<>();
    List<TFileInfo> enclosureFileList = new ArrayList<>();
    for (MultipartFile multipartFile : artificialParam.getInvoiceFile()) {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(multipartFile, path, multipartFile.getOriginalFilename());
      tFileInfo.setType(2);
      tFileInfo.setArtificialId(artificialId);
      invoiceFileList.add(tFileInfo);
    }
    for (MultipartFile multipartFile : artificialParam.getPassbookFile()) {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(multipartFile, path, multipartFile.getOriginalFilename());
      tFileInfo.setType(1);
      tFileInfo.setArtificialId(artificialId);
      passbookFileList.add(tFileInfo);
    }
    for (MultipartFile multipartFile : artificialParam.getEnclosureFile()) {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(multipartFile, path, multipartFile.getOriginalFilename());
      tFileInfo.setType(4);
      tFileInfo.setArtificialId(artificialId);
      enclosureFileList.add(tFileInfo);
    }
    if ((CollectionUtils.isEmpty(invoiceFileList) || saveBatch(invoiceFileList)) &&
        (CollectionUtils.isEmpty(passbookFileList) || saveBatch(passbookFileList)) &&
        (CollectionUtils.isEmpty(enclosureFileList) || saveBatch(enclosureFileList))) {
      uploadList(artificialParam.getInvoiceFile(), invoiceFileList);
      uploadList(artificialParam.getPassbookFile(), passbookFileList);
      uploadList(artificialParam.getEnclosureFile(), enclosureFileList);
      return uploadListFtp(invoiceFileList) && uploadListFtp(passbookFileList) && uploadListFtp(enclosureFileList);
    }
    return false;
  }
  
  @Override
  public Boolean uploadArtificial(ArtificialParam artificialParam, String artificialId) throws IOException {
    return uploadArtificial(artificialParam, artificialId, filePath);
  }
  
  @SneakyThrows
  @Override
  public List<WiteoffAttchment> uploadOpenFile(List<WiteoffAttchment> attchments) {
    if (CollectionUtils.isEmpty(attchments)) {
      return null;
    }
    List<TFileInfo> fileList = new ArrayList<>();
    attchments.stream().forEach(attchment -> {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(attchment.getFile(), filePath, attchment.getFile().getOriginalFilename());
      if(attchment.getFileType()==2) {
        tFileInfo.setType(2);
      }
      else {
        tFileInfo.setType(4);
      }
      upload(attchment.getFile(), tFileInfo.getPath());
      save(tFileInfo);
      if(tFileInfo.getType()==2)
      {
        TFileOpenElectronicFtp ftp = ftpService.uploadOpenElectronicFile(tFileInfo);
        attchment.setWiteoffAttchment(ftp);
      }
      else
      {
        TFileOpenEnclosureFtp ftp = ftpService.uploadOpenEnclosureFile(tFileInfo);
        attchment.setWiteoffAttchment(ftp);
      }
      //上传完后，删除文件
      attchment.setFile(null);
      fileList.add(tFileInfo);
    });
    
    return attchments;
  }
  
  @Override
  public Boolean uploadAppendixByType(List<MultipartFile> multipartFiles, Integer type, String id, String path) throws IOException {
    List<TFileInfo> fileList = new ArrayList<>();
    for (MultipartFile multipartFile : multipartFiles) {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(multipartFile, path, multipartFile.getOriginalFilename());
      tFileInfo.setType(3);
      if (type == 1) {
        tFileInfo.setPassbookId(id);
      } else if (type == 2) {
        tFileInfo.setInvoiceId(id);
      }
      fileList.add(tFileInfo);
    }
    if (saveBatch(fileList)) {
      uploadList(multipartFiles, fileList);
      return uploadListFtp(fileList);
    }
    return false;
  }
  
  @Override
  public Boolean uploadAppendixByType(List<MultipartFile> multipartFiles, Integer type, String id) throws IOException {
    return uploadAppendixByType(multipartFiles, type, id, filePath);
  }
  
  @Override
  public Boolean uploadFileByType(List<MultipartFile> multipartFiles, Integer type, String id, String path) throws IOException {
    List<TFileInfo> fileList = new ArrayList<>();
    for (MultipartFile multipartFile : multipartFiles) {
      TFileInfo tFileInfo = createTFileInfoByMultipartFile(multipartFile, path, multipartFile.getOriginalFilename());
      tFileInfo.setType(type);
      if (type == 1) {
        tFileInfo.setPassbookId(id);
      } else if (type == 2) {
        tFileInfo.setInvoiceId(id);
      }
      fileList.add(tFileInfo);
      System.out.println(tFileInfo);
    }
    System.out.println(type);
    System.out.println(fileList);
    if (saveBatch(fileList)) {
      uploadList(multipartFiles, fileList);
      return uploadListFtp(fileList);
    }
    return false;
  }
  
  @Override
  public Boolean uploadFileByType(List<MultipartFile> multipartFiles, Integer type, String id) throws IOException {
    return uploadFileByType(multipartFiles, type, id, filePath);
  }
  
  @Override
  public Boolean uploadFile(String acct, MultipartFile file, String name, String passbookId, String path) throws IOException {
    TFileInfo tFileInfo = createTFileInfoByMultipartFile(acct, file, path, name);
    tFileInfo.setType(1);
    tFileInfo.setPassbookId(passbookId);
    if (save(tFileInfo)) {
      upload(file, tFileInfo.getPath());
      return true;
//      return uploadFtp(tFileInfo);
    }
    return null;
  }

  @Override
  public Boolean uploadPdf2Ftp() throws IOException {
    List<TFileInfo> tFileInfos=this.baseMapper.selectNeedUploadFtp();
    return uploadListFtp(tFileInfos);
  }

  
  @Override
  public Boolean uploadFile(MultipartFile file, String name, String path) throws IOException {
    TFileInfo tFileInfo = createTFileInfoByMultipartFile(file, path, name);
    if (save(tFileInfo)) {
      upload(file, tFileInfo.getPath());
      return uploadFtp(tFileInfo);
    }
    return null;
  }
  
  @Override
  public Boolean uploadFile(MultipartFile file, String name) throws IOException {
    return uploadFile(file, name, filePath);
  }
  
  @Override
  public Boolean uploadFile(MultipartFile file) throws IOException {
    return uploadFile(file, file.getOriginalFilename(), filePath);
  }
  
  @Override
  public Boolean uploadFile(List<MultipartFile> multipartFiles, String path) throws IOException {
    List<TFileInfo> fileList = new ArrayList<>();
    for (MultipartFile multipartFile : multipartFiles) {
      fileList.add(createTFileInfoByMultipartFile(multipartFile, path, multipartFile.getOriginalFilename()));
    }
    if (saveBatch(fileList)) {
      uploadList(multipartFiles, fileList);
      return uploadListFtp(fileList);
    }
    return false;
  }
  
  @Override
  public Boolean uploadFile(List<MultipartFile> multipartFiles) throws IOException {
    return uploadFile(multipartFiles, filePath);
  }
  
  @Override
  public Boolean softDelete(List<String> id) {
    List<TFileInfo> fileInfoList = new ArrayList<>();
    for (String str : id) {
      TFileInfo tFileInfo = getById(str);
      tFileInfo.setIsDelete(0);
      fileInfoList.add(tFileInfo);
    }
    return updateBatchById(fileInfoList);
  }
  
  @Override
  public void acctDownload(HttpServletRequest request, HttpServletResponse response, String id) throws UnsupportedEncodingException {
    
    TFileInfo tFileInfo = this.baseMapper.selectById(id);
    response.setCharacterEncoding(request.getCharacterEncoding());
    response.setContentType("application/pdf");
    FileInputStream fis = null;
    try {
      File file = new File(tFileInfo.getPath());
      fis = new FileInputStream(file);
      response.setHeader("Content-Disposition", "attachment; filename=\"" + tFileInfo.getName() + "\"");
      IOUtils.copy(fis, response.getOutputStream());
      response.flushBuffer();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (fis != null) {
        try {
          fis.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    
  }

  @Override
  public void acctDownloadZip(HttpServletRequest request, HttpServletResponse response, List<String> id) throws IOException {
    List<TFileInfo> tFileInfos=this.baseMapper.selectBatchIds(id);

    File file = File.createTempFile("acctDownloadZip",".zip");

    ZipOutputStream zos = null;
    try {
      zos = new ZipOutputStream(new FileOutputStream(file));
      for (TFileInfo tFileInfo : tFileInfos) {
        // 递归压缩文件
        File InfoFile = new File(tFileInfo.getPath());
        String relativePath = InfoFile.getName();
        if (file.isDirectory()) {
          relativePath += File.separator;
        }
        zipFile(InfoFile, relativePath, zos);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (zos != null) {
          zos.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    response.setCharacterEncoding(request.getCharacterEncoding());
    response.setContentType("application/pdf");
    FileInputStream fis = null;
    try {
      fis = new FileInputStream(file);
      response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
      IOUtils.copy(fis, response.getOutputStream());
      response.flushBuffer();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (fis != null) {
        try {
          fis.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    file.deleteOnExit();
  }

  private static void zipFile(File file, String relativePath, ZipOutputStream zos) {
    InputStream is = null;
    try {
      if (!file.isDirectory()) {
        ZipEntry zp = new ZipEntry(relativePath);
        zos.putNextEntry(zp);
        is = new FileInputStream(file);
        byte[] buffer = new byte[1024];
        int length = 0;
        while ((length = is.read(buffer)) >= 0) {
          zos.write(buffer, 0, length);
        }
        zos.flush();
        zos.closeEntry();
      } else {
        String tempPath = null;
        for (File f : file.listFiles()) {
          tempPath = relativePath + f.getName();
          if (f.isDirectory()) {
            tempPath += File.separator;
          }
          zipFile(f, tempPath, zos);
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (is != null) {
          is.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  @Override
  public List<TFileInfo> saveInvoiceFile(byte[] fileData,String date,String nsrsbh) throws IOException {
    String path=filePath+"odf/"+date+"/"+nsrsbh+"/";
    ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(fileData));
    List<TFileInfo> tFileInfos=new ArrayList<>();
    ZipEntry entry;
    //遍历压缩文件内部 文件数量
    while((entry = in.getNextEntry()) != null){
      if(!entry.isDirectory() && CollectionUtils.isEmpty(baseMapper.selectByInvoiceIdTFileInfos(entry.getName().split("\\.")[0]))){
        TFileInfo tFileInfo=new TFileInfo(entry,path+entry.getName());
        tFileInfos.add(tFileInfo);
        File tFile = new File(path);
        if (!tFile.exists()) {//如果文件夹不存在
          tFile.mkdirs();//创建文件夹
        }
        //文件输出流
        FileOutputStream out = new FileOutputStream( path+entry.getName());
        BufferedOutputStream bos = new BufferedOutputStream(out);
        int len;
        byte[] buf = new byte[1024];
        while ((len = in.read(buf)) != -1) {
          bos.write(buf, 0, len);
        }
        // 关流顺序，先打开的后关闭
        bos.close();
        out.close();
      }
    }
    saveBatch(tFileInfos);
    return tFileInfos;
  }

  //将文件转换为基础的TfileInfo
  private TFileInfo createTFileInfoByMultipartFile(String acct, MultipartFile file, String path, String name) {
    
    File tFile = new File(path);
    if (!tFile.exists()) {//如果文件夹不存在
      tFile.mkdirs();//创建文件夹
    }
    
    TFileInfo tFileInfo = new TFileInfo();
    tFileInfo.setName(file.getOriginalFilename());
    tFileInfo.setContentType(file.getContentType());
    tFileInfo.setSize(file.getSize());
    tFileInfo.setPath(path +
        new SimpleDateFormat("yyyyMMddHHmm").format(new Date())
        + name);
    tFileInfo.setIsDelete(1);
    tFileInfo.setCreateBy(acct);
    return tFileInfo;
  }
  
  //将文件转换为基础的TfileInfo
  private TFileInfo createTFileInfoByMultipartFile(MultipartFile file, String path, String name) {
    
    File tFile = new File(path);
    if (!tFile.exists()) {//如果文件夹不存在
      tFile.mkdirs();//创建文件夹
    }
    
    TFileInfo tFileInfo = new TFileInfo();
    tFileInfo.setName(file.getOriginalFilename());
    tFileInfo.setContentType(file.getContentType());
    tFileInfo.setSize(file.getSize());
    tFileInfo.setPath(path +
        new SimpleDateFormat("yyyyMMddHHmm").format(new Date())
        + name);
    tFileInfo.setIsDelete(1);
//        tFileInfo.setCreateBy(userInfoService.getCurrentAcctId());
    return tFileInfo;
  }
  
  //批量保存文件
  private void uploadList(List<MultipartFile> fileList, List<TFileInfo> tFileInfoList) throws IOException {
    for (int i = 0; i < fileList.size(); i++) {
      upload(fileList.get(i), tFileInfoList.get(i).getPath());
    }
  }
  
  //保存文件
  @SneakyThrows
  private void upload(MultipartFile file, String path) {
    file.transferTo(new File(path));
  }
  
  //将文件上传至ftp
  private Boolean uploadListFtp(List<TFileInfo> tFileInfos) throws IOException {
    boolean re = true;
    for (TFileInfo tFileInfo : tFileInfos) {
      re = re && uploadFtp(tFileInfo);
    }
    return re;
  }
  
  private Boolean uploadFtp(TFileInfo tFileInfo) throws IOException {
    if (tFileInfo.getArtificialId() == null && tFileInfo.getPassbookId() == null && tFileInfo.getInvoiceId() == null) {
      return ftpService.uploadEnclosure(tFileInfo.getId());
    } else {
      return ftpService.uploadElectronic(tFileInfo.getId());
    }
  }
}
